﻿using Angle.Krill.SystemConfig;
using AntdUI.Svg;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Angle.Krill.Utils
{
    public static class FileHelper
    {
        public static void ProcessStart(string filePath, Action fileLockCallback = null)
        {
            if (IsFileLocked(filePath))
            {
                fileLockCallback?.Invoke();
            }
            else
            {
                System.Diagnostics.Process.Start(filePath);
            }
        }
        public static void ProcessStart(ProcessStartInfo processStartInfo)
        {
            System.Diagnostics.Process.Start(processStartInfo);
        }
        /// <summary>
        /// 通过文件选择窗口获取文件路径
        /// </summary>
        /// <param name="filter">文件过滤字符串</param>
        /// <returns></returns>
        public static string GetOpenFilePath(string filter = "")
        {
            string filePath = string.Empty;
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Title = "请选择文件";
            if (!string.IsNullOrEmpty(filter))
            {
                ofd.Filter = filter;
            }
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                filePath = ofd.FileName;
            }

            return filePath;
        }
        /// <summary>
        /// 选择文件夹
        /// </summary>
        /// <returns></returns>
        public static string GetOpenFolderPath()
        {
            string selectedFolderPath = string.Empty;
            using (FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog())
            {
                folderBrowserDialog.Description = "选择文件夹";

                string rootPath = SysConfigHelper.Instance.SysConfig.MainConfig.LastAcessFolderPath;
                if (string.IsNullOrEmpty(SysConfigHelper.Instance.SysConfig.MainConfig.LastAcessFolderPath))
                {
                    folderBrowserDialog.RootFolder = Environment.SpecialFolder.MyComputer;
                }
                else
                {
                    folderBrowserDialog.SelectedPath = rootPath;
                }
                folderBrowserDialog.ShowNewFolderButton = true;

                DialogResult dialogResult = folderBrowserDialog.ShowDialog();

                if (dialogResult == DialogResult.OK)
                {
                    selectedFolderPath = folderBrowserDialog.SelectedPath;

                    SysConfigHelper.Instance.SysConfig.MainConfig.LastAcessFolderPath = selectedFolderPath;
                }
            }

            return selectedFolderPath;
        }
        /// <summary>
        /// 获取保存文件的文件夹路径
        /// </summary>
        /// <param name="defaultName">默认文件名称</param>
        /// <param name="extendName">文件扩展名</param>
        /// <param name="fileStream">文件的输出流</param>
        /// <returns></returns>
        public static string GetSaveFilePath(string defaultName, string extendName, out FileStream fileStream)
        {
            string filePath = string.Empty;
            fileStream = null;

            SaveFileDialog sfd = new SaveFileDialog();
            sfd.FileName = defaultName;
            sfd.DefaultExt = extendName;
            sfd.RestoreDirectory = true;
            if (sfd.ShowDialog() == DialogResult.OK)
            {
                filePath = sfd.FileName;

                fileStream = (FileStream)sfd.OpenFile();
            }

            return filePath;
        }
        /// <summary>
        /// 获取指定文件夹中的文件及文件夹及其中文件
        /// </summary>
        /// <param name="folderPath">文件夹路径</param>
        /// <param name="filter">扩展名过滤</param>
        /// <returns></returns>
        public static List<FolderInfoExt> GetFiles(string folderPath, string filter, int depth = 0)
        {
            List<FolderInfoExt> listFolder = new List<FolderInfoExt>();
            DirectoryInfo directoryInfo;
            if (folderPath.EndsWith("\\"))
                directoryInfo = new DirectoryInfo(folderPath);
            else
                directoryInfo = new DirectoryInfo(folderPath.Substring(0, folderPath.LastIndexOf("\\")));

            listFolder = GetFolderFiles(folderPath, directoryInfo, filter, depth);

            return listFolder;
        }

        public static List<FolderInfoExt> GetFolderFiles(string rootFolderPath, DirectoryInfo directoryInfo, string filter, int depth = 0)
        {
            List<FolderInfoExt> listFolders = new List<FolderInfoExt>();
            if (depth < 0)
            {
                return listFolders;
            }

            depth--;
            try
            {
                FolderInfoExt folderInfoExt = null;
                DirectoryInfo[] dirs = directoryInfo.GetDirectories();
                foreach (DirectoryInfo dir in dirs)
                {
                    folderInfoExt = new FolderInfoExt();
                    folderInfoExt.FolderName = dir.Name;
                    folderInfoExt.FolderPath = dir.FullName;
                    folderInfoExt.FileCollection = GetFiles(rootFolderPath, dir, filter, depth);
                    folderInfoExt.FolderCollection = GetFolderFiles(rootFolderPath, dir, filter, depth);

                    listFolders.Add(folderInfoExt);
                }
            }
            catch (Exception ex)
            {
                LoggerHelper.Error("读取文件夹文件异常，详见异常信息", ex);
            }

            return listFolders;
        }

        public static List<FileInfoExt> GetFiles(string rootFolderPath, DirectoryInfo directoryInfo, string filter, int depth = 0)
        {
            List<FileInfoExt> listFileInfo = new List<FileInfoExt>();
            try
            {
                FileInfo[] files = string.IsNullOrEmpty(filter) ? directoryInfo.GetFiles() : directoryInfo.GetFiles("*." + filter);

                foreach (FileInfo fi in files)
                {
                    listFileInfo.Add(new FileInfoExt
                    {
                        Name = fi.Name,
                        NameWithoutExtend = Path.GetFileNameWithoutExtension(fi.Name),
                        PhysicalPath = fi.FullName,
                        RelativePath = fi.FullName.Substring(rootFolderPath.Length),
                        Size = fi.Length,
                        LastModifyDatetime = fi.LastWriteTime
                    });
                }
            }
            catch (Exception ex)
            {
                LoggerHelper.Error("读取文件夹文件异常，详见异常信息", ex);
            }


            return listFileInfo;
        }

        public static FolderInfoExt GetFolderAndFiles(string dirName, int depth = 0)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(dirName);

            FolderInfoExt lst = new FolderInfoExt
            {
                FolderName = Path.GetFileName(dirName),
                FolderPath = dirName,
                FileCollection = GetFiles(directoryInfo),
                FolderCollection = GetFolderFiles(directoryInfo, depth)
            };

            return lst;
        }

        private static List<FolderInfoExt> GetFolderFiles(DirectoryInfo directoryInfo, int depth)
        {
            List<FolderInfoExt> listFolders = new List<FolderInfoExt>();
            if (depth < 0)
            {
                return listFolders;
            }

            depth--;
            try
            {
                FolderInfoExt folderInfoExt = null;
                DirectoryInfo[] dirs = directoryInfo.GetDirectories();
                foreach (DirectoryInfo dir in dirs)
                {
                    folderInfoExt = new FolderInfoExt();
                    folderInfoExt.FolderName = dir.Name;
                    folderInfoExt.FolderPath = dir.FullName;
                    folderInfoExt.FileCollection = GetFiles(dir);
                    folderInfoExt.FolderCollection = GetFolderFiles(dir, depth);

                    listFolders.Add(folderInfoExt);
                }
            }
            catch (Exception ex)
            {
                LoggerHelper.Error("读取文件夹文件异常，详见异常信息", ex);
            }

            return listFolders;
        }

        public static List<FileInfoExt> GetFiles(DirectoryInfo directoryInfo)
        {
            List<FileInfoExt> listFileInfo = new List<FileInfoExt>();
            try
            {
                FileInfo[] files = directoryInfo.GetFiles();

                foreach (FileInfo fi in files)
                {
                    listFileInfo.Add(new FileInfoExt
                    {
                        Name = fi.Name,
                        NameWithoutExtend = Path.GetFileNameWithoutExtension(fi.Name),
                        PhysicalPath = fi.FullName,
                        Size = fi.Length,
                        LastModifyDatetime = fi.LastWriteTime
                    });
                }
            }
            catch (Exception ex)
            {
                LoggerHelper.Error("读取文件夹文件异常，详见异常信息", ex);
            }

            return listFileInfo;
        }
        /// <summary>
        /// 移动文件
        /// </summary>
        /// <param name="desPath">目标路径</param>
        /// <param name="srcFilePath">源文件</param>
        /// <param name="isCover">是否覆盖</param>
        internal static void MoveFile(string desPath, string srcFilePath, Func<string, bool> sameNameAction = null, Action fileLockCallback = null)
        {
            string newFilePath = VerifyFilePath(ref desPath, srcFilePath, sameNameAction);

            if (IsFileLocked(srcFilePath))
            {
                fileLockCallback?.Invoke();
            }
            else
            {
                File.Move(srcFilePath, newFilePath);
            }
        }

        /// <summary>
        /// 拷贝文件
        /// </summary>
        /// <param name="desPath">目标路径</param>
        /// <param name="srcFilePath">源文件</param>
        /// <param name="isCover">是否覆盖</param>
        internal static void CopyFile(string desPath, string srcFilePath, Func<string, bool> sameNameAction = null)
        {
            string newFilePath = VerifyFilePath(ref desPath, srcFilePath, sameNameAction);

            File.Copy(srcFilePath, newFilePath);
        }
        /// <summary>
        /// 拷贝文件
        /// </summary>
        /// <param name="desPath">目标路径</param>
        /// <param name="srcFilePath">源文件</param>
        /// <param name="isCover">是否覆盖</param>
        internal static void DelFile(string filePath, Action fileLockCallback = null)
        {
            if (IsFileLocked(filePath))
            {
                fileLockCallback?.Invoke();
            }
            else
            {
                File.Delete(filePath);
            }
        }
        /// <summary>
        /// 创建文件
        /// </summary>
        /// <param name="filePath"></param>
        internal static void CreateFile(string filePath, Action fileExistCallback, Action successCallback)
        {
            if (File.Exists(filePath))
            {
                fileExistCallback?.Invoke();
            }
            else
            {
                string dirPath = Path.GetDirectoryName(filePath);
                if (!Directory.Exists(dirPath))
                {
                    Directory.CreateDirectory(dirPath);
                }

                File.Create(filePath);

                successCallback?.Invoke();
            }
        }

        internal static void CreateFolder(string folderPath, Action folderExistCallback, Action successCallback)
        {
            if (!Directory.Exists(folderPath))
            {
                Directory.CreateDirectory(folderPath);
                successCallback?.Invoke();
            }
            else
            {
                folderExistCallback?.Invoke();
            }
        }

        internal static bool IsFileLocked(string filePath)
        {
            try
            {
                using (FileStream fs = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                LoggerHelper.Error($"文件被占用", ex);

                return true;
            }
        }

        private static string VerifyFilePath(ref string desPath, string srcFilePath, Func<string, bool> sameNameAction = null, Action fileLockCallback = null)
        {
            if (!Directory.Exists(desPath))
            {
                desPath = Path.GetDirectoryName(desPath);
            }
            string fileName = Path.GetFileName(srcFilePath);
            string newFilePath = Path.Combine(desPath, fileName);
            if (File.Exists(newFilePath))
            {
                bool isCover = sameNameAction?.Invoke(fileName) ?? true;
                if (isCover)
                {
                    FileHelper.DelFile(newFilePath, fileLockCallback);
                }
                else
                {
                    string newName = $"{Path.GetFileNameWithoutExtension(fileName)}({DateTime.Now.ToString("yyyyMMddHHmmss")}){Path.GetExtension(fileName)}";
                    newFilePath = Path.Combine(desPath, $"{newName}");
                }
            }

            return newFilePath;
        }
        public static string GetPathForUserAppDataFolder(string subPath = "")
        {
            string appPath = null;
            if (appPath == null)
            {
                appPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Krill");
                if (!Directory.Exists(appPath))
                {
                    Directory.CreateDirectory(appPath);
                }
            }

            return Path.Combine(appPath, subPath);
        }

        internal static string GetPathForStartupFolder(string subPath = "")
        {
            string executablePath = Process.GetCurrentProcess().MainModule.FileName;
            string startupPath = Path.GetDirectoryName(executablePath);

            return Path.Combine(startupPath, subPath);
        }
    }

    /// <summary>
    /// 文件集合树
    /// </summary>
    public class FolderInfoExt
    {
        private string folderName = string.Empty;
        private string folderPath = string.Empty;
        private List<FolderInfoExt> folderCollection = new List<FolderInfoExt>();
        private List<FileInfoExt> fileCollection = new List<FileInfoExt>();

        /// <summary>
        /// 当前文件夹名称
        /// </summary>
        public string FolderName { get => folderName; set => folderName = value; }
        /// <summary>
        /// 当前文件夹路径
        /// </summary>
        public string FolderPath { get => folderPath; set => folderPath = value; }
        /// <summary>
        /// 路径下包含文件夹集合
        /// </summary>
        public List<FolderInfoExt> FolderCollection { get => folderCollection; set => folderCollection = value; }
        /// <summary>
        /// 路径下包含的文件集合
        /// </summary>
        public List<FileInfoExt> FileCollection { get => fileCollection; set => fileCollection = value; }
    }
    /// <summary>
    /// 文件信息集
    /// </summary>
    public class FileInfoExt
    {
        /// <summary>
        /// 文件名称
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 没有扩展的文件名称
        /// </summary>
        public string NameWithoutExtend { get; set; }
        /// <summary>
        /// 相对路径
        /// </summary>
        public string RelativePath { get; set; }
        /// <summary>
        /// 绝对路径
        /// </summary>
        public string PhysicalPath { get; set; }
        /// <summary>
        /// 大小
        /// </summary>
        public long Size { get; set; }
        /// <summary>
        /// 最后修改时间
        /// </summary>
        public DateTime LastModifyDatetime { get; set; }
    }
}
